var JBCore = Class.create();

JBCore.prototype = {
    initialize: function() {
    },
    
    droppables : new Array(),

    initializeRuntime: function() {
      
      JB.showError();
      if(initializeEditor) initializeEditor();
      if(jbDesigner)
        jbDesigner.initializeRuntime();
    
    },
    REQ_COMP_ID : "jbCompId",
    RES_COMP_ID : "jbRespId",

    StateMachine :
    {
      pp : new Array(),
      scrollPos : {left:0,top:0},
      addPos : function(array, reqCompId) {
        this.scrollPos.top = $(reqCompId).scrollTop; 
        this.scrollPos.left = $(reqCompId).scrollLeft;
        array[array.length] = {id:reqCompId, scroll:this.scroolPos};
        $A($(reqCompId).childNodes).each(function(item) {
                return JB.StateMachine.addPos(array, item.id);
            }
        );
        return array;
      },
      saveState : function(reqCompId)
      {
      //find all the scrollpo
        this.scrollPos.top = $(reqCompId).scrollTop; 
        this.scrollPos.left = $(reqCompId).scrollLeft;
        /*
        pp[pp.length] = {id:reqCompId, scroll:this.scroolPos};
        this.pp = new Array();
        this.pp = this.addPos(pp, reqComId);
        */
      },
      restoreState:function(reqCompId)
      {
      //restore all scrollpos
        $(reqCompId).scrollTop=this.scrollPos.top;    
        $(reqCompId).scrollLft=this.scrollPos.left;    
      },
      //render resCompId
      rerender : function(resCompId, newHTML)
      { 
        try
        {
            this.saveState(resCompId);
            $(resCompId).innerHTML = newHTML;
            this.restoreState(resCompId);
            newHTML.evalScripts();
            JB.stretch(resCompId);
        }catch( e)
        {
            log(resCompId, ' rerender ', JBDebugger.EXCEPTION);
        }
      },
      renderComp : function(resCompId, newHTML)
      { 
        try
        {
            this.saveState(resCompId);
            Element.replace(resCompId, newHTML);
            this.restoreState(resCompId);
        }catch( e)
        {
            log(resCompId, ' rerender ', JBDebugger.EXCEPTION);
        }
      }
    },

  dialogBoxName : 'dialogFrame',
  submitForm : function(formCompId, reqCompId)
  {
    formId='f'+formCompId;
    url = $(formId).action;
    url = url + '&'+'editAction=processRequest&' + JB.REQ_COMP_ID + '=' 
        + formCompId + '&' + JB.RES_COMP_ID+'='+reqCompId;   
    
    url = url + '&'+Form.serialize(formId);

    JB.Ajax.post(url, '', 
        function (transport)
        {
          try
          {
            JB.StateMachine.rerender(reqCompId, transport.responseText);
          }catch( e)
          {
            log(reqCompId, ' failed to rerender  ', JBDebugger.EXCEPTION);
          }
        }, null, null
     );
  },
  sortList: function (listId, column) {
      JB.setComponentProperty(listId, 'sortBy', column, null, true);
  },
  
  /**
  * call when a splitter panel finish moving. Splitter splits p1, and p2. All
  * of these panels must be child of parant. 
  * Values for direction is either horizontal or vertical
  */
  splitterMoved : function(splitter, p1, p2, parent, direction)
  { 
    if(!JB.assertNull([splitter, p1, p2]))
    {
        return false;
    }

    var percent;

    if($(splitter).percent && direction=='horizontal')
    {
        percent = $(splitter).percent.x;              
        parentRect = JavaBase.Dimension.getElementRect(parent);
        parentWidth=parentRect.width;
        $(p1).style.width = (parentWidth*percent/100) + 'px';
        $(p2).style.width = (parentWidth*(1-percent/100) - Element.getWidth(splitter)) + 'px';
    }
    
    if($(splitter).percent && direction=='vertical')
    {
        percent = $(splitter).percent.y;
        parentRect = JavaBase.Dimension.getElementRect(parent);
        parentHeight=parentRect.height;
        $(splitter).style.width = '';
        $(p1).style.height = parentHeight*percent/100 + 'px';
        $(p2).style.height = (parentHeight*(1-percent/100) - Element.getHeight(splitter)) + 'px';
    }
    this.resizeChildren(p1);//, direction);
    this.resizeChildren(p2);//, direction);
    JBStretchBody();
    JB.synchDim(p1);
    JB.synchDim(p2);
    JB.synchDim(splitter);
  },
  splitterImages:function(img, element) {
      Element.toggle(element);
      if($(img).src.indexOf('images/windows/Back.gif')!=-1)
         $(img).src='images/windows/Next.gif';
      else
         $(img).src='images/windows/Back.gif';
      JBStretchBody();
  },
  //
  assertNull: function(eles) {
    var message='Following element not defined ';
    var seccuss=true;
    
      eles.each(
        function(ele)
        {
            if(!$(ele))
            {
                message += "<br/>"+ele;
                seccuss=false;
            }
        }
      );
      if(!seccuss)
        JB.messageBox(message);
      return seccuss;
  },
  //
  //layout all the myNodes
  //from parent to child
  //
  stretch : function(eleId) {
      var ele = $(eleId);
      if(ele==null)
        return;

      if(ele.tagName!='DIV' && ele.tagName!='BODY')
      {
        return;
      } 

      var myNodes = ele.childNodes;
      var parentRect = JavaBase.Dimension.getElementRect(ele, false);
      
      if(ele.tagName=='BODY')
      {
        parentRect = JavaBase.Dimension.getWindowRect();
      }

      var stretchV = null;
      var yTotal = 0;
      var stretchH = null;
      var xTotal = 0;
      var i = 0;
      var child=null;
      for (i = 0; i < myNodes.length; i++) 
      {
         child = myNodes[i];
         if(child !='undefined' 
            && child.id!='undefined' 
            && child.id!=null
            && (child.tagName=='DIV' || child.tagName == 'TABLE')
            && child.style.position!='absolute' 
            && child.style.display!='none'
            && child.id!='designPad' 
            && child.id!='debugBoxc' && !Element.hasClassName(child, 'jbMenuDiv')
         )
         {
            childRect = {width:Element.getWidth(child), height:Element.getHeight(child)};
            //JavaBase.Dimension.getElementRect(child, true);
            if(child.getAttribute("stretch")=='vertical' || child.getAttribute("stretch")=='both')
            {
                stretchV = child;
            }else
            {
                yTotal += childRect.height;
            }
            
            if(child.getAttribute("stretch")=='horizontal' || child.getAttribute("stretch")=='both')
                stretchH = child;
            else
            {
                xTotal += childRect.width;
            }
         }
      }      
      if(stretchV!=null) {  
          var bh = (stretchV.style.borderTopWidth ?  parseInt(stretchV.style.borderTopWidth):0)
          +(stretchV.style.borderBottomWidth ?  parseInt(stretchV.style.borderBottomWidth):0);
          var ph = (stretchV.style.paddingTop ?  parseInt(stretchV.style.paddingTop):0)+
          (stretchV.style.paddingBottom ?  parseInt(stretchV.style.paddingBottom):0);
          var bh1 = (ele.style.borderTopWidth ?  parseInt(stretchV.style.borderTopWidth):0)
          +(stretchV.style.borderBottomWidth ?  parseInt(stretchV.style.borderBottomWidth):0);
          var ph1 = (ele.style.paddingTop ?  parseInt(ele.style.paddingTop):0)+
          (ele.style.paddingBottom ?  parseInt(ele.style.paddingBottom):0);

          stretchV.style.height= (parentRect.height - bh1 - ph1 - yTotal - bh - ph - 1) +'px';
      }
      
      if(stretchH!=null) {
          var bw = (stretchH.style.borderLeftWidth ?  parseInt(stretchH.style.borderLeftWidth):0)
          +(stretchH.style.borderRightWidth ?  parseInt(stretchH.style.borderRightWidth):0);
          var pw = (stretchH.style.paddingLeft ?  parseInt(stretchH.style.paddingLeft):0)
          + (stretchH.style.paddingRight ?  parseInt(stretchH.style.paddingRight):0);

          var bw1 = (ele.style.borderLeftWidth ?  parseInt(ele.style.borderLeftWidth):0)
          +(ele.style.borderRightWidth ?  parseInt(ele.style.borderRightWidth):0);
          var pw1 = (ele.style.paddingLeft ?  parseInt(ele.style.paddingLeft):0)
          + (ele.style.paddingRight ?  parseInt(ele.style.paddingRight):0);

          stretchH.style.width= (parentRect.width - xTotal - 1 - bw1 - pw1 - bw - pw) +'px';
      }
      
      for (i = 0; i < myNodes.length; i++) 
      {
         child = myNodes[i];
         if(child.tagName=='DIV'             
          //  && child.style.position!='absolute' 
            && child.style.display!='none'
        //    && child.id!='designPad' 
         //   && child.id!='debugBoxc'
            )
            this.stretch(child);
      }
  },
  
  //resize the chidren of element, direction 
  resizeChildren : function (element, direction) {
      var ele = $(element);
      if(ele==null)
        return;

      var myNodes = ele.childNodes;

      var parentRect = JavaBase.Dimension.getElementRect(ele);
      var stretchEle = null;
      var total= 0;
      var child=null;
      var i=0;
     
      for (i = 0; i < myNodes.length; i++) 
      {
         child = myNodes[i];
         if(child.id)
         {
            childRect = JavaBase.Dimension.getElementRect(child);
            if(child.getAttribute("stretch")=='vertical')
                stretchEle = child;
            else
            {
                total += childRect.height;
            }
         }
      };
      
      if(stretchEle!=null) {
          stretchEle.style.height= (parentRect.height - total) +'px';
      }
      for (i = 0; i < myNodes.length; i++) 
      {
         child = myNodes[i];
         if(child.id)
         {
            this.resizeChildren(child, direction);
         }
      };
  },
  
  splitterLoaded : function(splitter, p1, p2, parent, direction)
  {
    if(direction=='horizontal')
    {
        parentRect = JavaBase.Dimension.getElementRect(parent);
        parentWidth=parentRect.width;
        $(p2).style.width = (parentWidth - parseInt($(p1).style.width) - parseInt($(splitter).style.width)) + 'px';
        this.resizeChildren(p1, direction);
        this.resizeChildren(p2, direction);
    }
    if(direction=='vertical')
    {
        parentRect = JavaBase.Dimension.getElementRect(parent);
        parentHeight=parentRect.height;
        $(p2).style.height = (parentHeight - parseInt($(p1).style.height) - parseInt($(splitter).style.height)) + 'px';
    }    
  },
  
  playBackground : function(url, loop)
  {
    if(url==null || url=='')
      return;

    if (javaBaseBrowser.ie || javaBaseBrowser.op)
    {
      if('true'==loop)
        document.writeln('<bgsound src="'+url+'" loop="infinite" />');
      else
        document.writeln('<bgsound src="'+url+'" />');
    }
  },
  jbLastPanel: null,
 /*
  * Display name panel with options
  * options include
  *   reference reference element
  *   left top width height
  *   exclusive
  */
  togglePanel :  function (panelName, options)
    {
      var panel = $(panelName);
      if(!panel) //does nothing
        return;

      if(options.exclusive && this.jbLastPanel!=null && this.jbLastPanel!=panel)
      {
          this.jbLastPanel.style.display='none';
      }
      
      var x = 0;
      var y = 10;

      if(options.reference)
      {
        pt = JavaBase.Dimension.getElementPosition(options.reference);
        x = pt.left + options.left;
        y = pt.top + options.top;
      }

      if(y)
        panel.style.top = y + "px";
    
      if(x)
        panel.style.left = x + "px";
    
      if(options.width>0)
        panel.style.width=options.width+"px";
    
      if(options.height>0)
        panel.style.height=options.height+'px';
    
      var display='block';
      if(panel.style.display=='none')
      {
        display='block';
      }else
      {
        display='none';
      }
      if(options.exclusive)
      {
        this.jbLastPanel = panel;
      }
    
      //synch up with server via ajax
      if(options.synchServer)
      {
        var ajaxCmd = new JB.AJaxCommand(window.location.href, "set", panelName, "clientId");
        ajaxCmd.addProperty('displayStyle', display);  
        ajaxCmd.addProperty('top', panel.style.top);  
        ajaxCmd.addProperty('left', panel.style.left);  
        ajaxCmd.post(
          function ()//callback
          {
            panel.style.display = display;
          }
        );
      }else
      {
        if(options.effect)
        {
            //
        }else
            panel.style.display = display;
      }
      return panel.style.display;
    },

  /**
    hide a dialog box created by showDialogBox
  **/
  hideDialogBox : function(panelName)
  {
      try
      {
        dialogBox = $(panelName);
        if(dialogBox==null)
          return;
        
        JBRectTool.popdown(panelName);
      }catch( e)
      {
        log(panelName, e.message, JBDebugger.EXCEPTION); 
      }
  },   
 /*
  * Create a panel defined in a different page
        options.callback a function to call 
  */
  createPanel : function(pageName, panelName, options)
  {
    var url = JBUtil.getUrl()+ '?editAction=renderPanel&pageName='+pageName+'&compName='+panelName;
    JB.Ajax.post(url, 'renderPanel',
        function (transport)
        {
          try
          { 
            if($(panelName))
              document.body.removeChild($(panelName));
              
            var div = document.createElement('div');
            div.id=panelName+"_div";
            div.innerHTML = transport.responseText;
            div.style.display='none';
            document.body.appendChild(div);
            
            dialogBox = $(panelName);
            if(dialogBox)
            {
                dialogBox.style.position='absolute';
                dialogBox.style.display='none';
                dialogBox.style.zIndex='100';
            
                document.body.appendChild(dialogBox);
                if(options && options.callback) 
                    options.callback(dialogBox);
            
                document.body.removeChild(div);
            }
          }catch( e)
          {
            log(panelName, e.message, JBDebugger.EXCEPTION); 
          }
        }, null, null
     );
  },
  renderComp : function(compId, options)
  {
    var url = JBUtil.getUrl()+ '?editAction=renderPanel&compName='+compId;
    JB.Ajax.post(url, 'renderPanel',
        function (transport)
        {
            JB.StateMachine.renderComp(compId, transport.responseText);
        }, null, null
     );
  },
   /**
   Show a panel defined in page by PageName in a popup window. 
   It calls on the server to render the
   panel, and dynamically render it as a popup window.
   @param pageName page where panel is defined
   @panel panel to be rendered as a popup window.
   options.ctrlEle element invoke this function
   options.modal default to true
   options.duration 
   **/
  showDialogBox : function(pageName, panelName, opts)
  {
    this.createPanel(pageName, panelName, {callback: function()
        {
            try{
                var options = Object.extend({
                    modal:true,
                    source:panelName
                }, opts || {});
                JBRectTool.popup(panelName, options);                
            }catch(e)
            {
                log(panelName, 'JB.showDialogBox ' + e.message, JBDebugger.EXCEPTION); 
            }
        }}
    );
  },
/**
 * Raise a server event
        options.componentId component to receive the event
        options.renderedId component to render if event is successfully handled
        options.waitingMessage message to display while waiting
        options.callback a function to call 
 **/
  raiseEvent : function(eventName, options)
  {
    this._e(JBUtil.getUrl(), 
        options.componentId, 
        eventName,
        options.renderedId,
        options.waitingMessage,
        options.callback);
  },
  
  raiseServerEvent : function(eventName, options)
  {
    var url = JBUtil.getUrl();
    if(url.indexOf("?")==-1)
      url = url+'?';
    else
      url = url+'&';

    url += 'version=new&editAction=serverEvent&eventName='+eventName;
    
    if(typeof(options.componentId)!='undefined'&&options.componentId!=null)
      url = url+ '&'+JB.REQ_COMP_ID+'='+options.componentId;   //source
    else
    {
        log("options.componentId must not be null to raise event!");
        return;
    }
        
    if(typeof(options.renderBackId)=='string' )
      url += '&'+JB.RES_COMP_ID+'='+options.renderBackId;   //render back

    var waitingMessage =options.waitingMessage?options.waitingMessage:'Please waiting...';
    var payload = options.payload?options.payload:'';
    
    JB.Ajax.post(url, options.payload, 
        function (transport)
        {
          //  alert(transport.responseText);
            if(typeof(options.renderBackId)=='string')
            {
                if(callback)
                {
                    try
                    {
                        callback(transport);
                    }catch (e)
                    {
                        log(reqCompId, 'raise event _e ' + e.message, JBDebugger.EXCEPTION); 
                    }
                }
                if(transport.responseText!='' && options.renderBack)
                {    
                //render return compo
                //TODO
                    if(options.renderBackId!=null)
                        Element.replace(options.renderBackId, transport.responseText);
                    else
                        Element.replace(options.componentId, transport.responseText);
                }
            }
        }, options.componentId, waitingMessage
     );
     return false;
  },  
/**
 * Raise a server event, and render the res id
 *  url request url
 *  reqCompId the component id the event is assigned to
 *  eventName name of the event, it is event handler name, assigned to onUpdate onView etc.
 *  resCompId the component to be rerendered
 *  waitingMsg a message to display while waiting for this
 *  callback procedure one the the call is done
 **/

  _e : function(url, reqCompId, eventName, resCompIds, waitingMsg, callback)
  {
    var urlStr = url;
    if(url.indexOf("?")==-1)
      url = url+'?';
    else
      url = url+'&';
    if(typeof(resCompIds)=='undefined'||resCompIds==null)
      url = url+ 'editAction=serverEvent&'+JB.REQ_COMP_ID+'='+reqCompId;   
    else if(typeof(resCompIds)=='string' )
      url = url+ 'editAction=serverEvent&'+JB.REQ_COMP_ID+'='+reqCompId+'&'+JB.RES_COMP_ID+'='+resCompIds;   
    else
      url = url+ 'editAction=serverEvent&'+JB.REQ_COMP_ID+'='+reqCompId+'&'+JB.RES_COMP_ID+'='+resCompIds[0];   
  
    if(typeof(waitingMsg)=='undefined')
      waitingMsg=false;
    else if(typeof(waitingMsg)=='boolean')
      waitingMsg =waitingMsg?'Please wait ...':false;
    else
      waitingMsg = waitingMsg?waitingMsg:'Please wait ...';

      
    JB.Ajax.post(url, eventName, 
        function (transport)
        {
          try
          {
          //  alert(transport.responseText);
            if(resCompIds==null)
            {
               JBUtil.reload();
            }else if(typeof(resCompIds)=='undefined')
            {
               JBUtil.reload();
            }else if(typeof(resCompIds)=='string')
            {
              if(transport.responseText!='')
              {    
                
                if(JB.hasError(transport)) {
                    JBUtil.reload();
                    return;
                }
                if(callback)
                {
                    try
                    {
                        if(callback(transport))
                            JB.StateMachine.rerender(resCompIds, transport.responseText);
                    }catch (e)
                    {
                        log(reqCompId, 'raise event _e ' + e.message, JBDebugger.EXCEPTION); 
                    }
                } else
                {
                   // alert(transport.responseText);
                    JB.StateMachine.rerender(resCompIds, transport.responseText);
                }
              }else
              {
                 log(reqCompId, 'raise event ', JBDebugger.INFO); 
              }
            }else if($(resCompIds[0]))
            {
              JavaBase.DomUtil.removemyNodesFromNode($(resCompIds[0]));
              $(resCompIds[0]).innerHTML=transport.responseText;
              if(resCompIds.length>1)
              {
                for(i=1; i<resCompIds.length;i++)
                {
                  this.renderChildren(resCompIds[i]);
                }
              }
            }else
            {
              JBUtil.reload();
            }
          }catch( e)
          {
             JBUtil.reload();
          }
        }, resCompIds, waitingMsg
     );
     return false;
   },

//reconcile with invoke
  execute : function(options)
  {
    var urlStr = JBUtil.getUrl();
    
    var ajaxCommand = new JB.AJaxCommand(urlStr, "invoke", options.component, "clientId");
    
    ajaxCommand.addProperty('methodName', options.method);
    if(!(!options.parameters))
        ajaxCommand.addProperty('parameters', options.parameters);

    if(options.resCompId)
      ajaxCommand.addProperty('jb.render.component', options.resCompId);
    
    ajaxCommand.post(function (transport)
        {
          if($(options.resCompId))
          {
            JB.StateMachine.rerender(resCompId, transport.responseText)
          }else {
            if($(options.component))
                Element.replace(options.component, transport.responseText);
          }

          if(options.onComplete) 
             options.onComplete(transport);
        }
    );
  },
  /*
    Sets property for a component. name must be a property of java
    object by componentId. On return, the server should try to render
    compoent resCompId
  */
  setComponentProperty : function(componentId, propertyName, propertyValue, onComplete, render)
  {
    var urlStr = JBUtil.getUrl();

    if(urlStr.indexOf("xsp#")>-1)
    {
      urlStr = urlStr.replace("xsp#","xsp");
    }
    var ajaxCommand = new JB.AJaxCommand(urlStr, "set", componentId, "clientId");
    if(propertyName instanceof Array)
    {
      for(i=0;i<propertyName.length;i++)
      {
        ajaxCommand.addProperty(propertyName[i], propertyValue[i]);
      }
    }else
      ajaxCommand.addProperty(propertyName, propertyValue);
        
    ajaxCommand.post(function (transport)
        {
            if(render)
                Element.replace(componentId, transport.responseText);
            if(onComplete)
            {
              onComplete();
            }
        }
    );
    return false;
  },
  //to be replaced
  setProperty : function(componentId, propertyName, propertyValue, resCompId, onComplete, pageName)
  {
    var urlStr = JBUtil.getUrl();

    if(urlStr.indexOf("xsp#")>-1)
    {
      urlStr = urlStr.replace("xsp#","xsp");
    }
    var ajaxCommand = new JB.AJaxCommand(urlStr, "set", componentId, "clientId");
    if(propertyName instanceof Array)
    {
      for(i=0;i<propertyName.length;i++)
      {
        ajaxCommand.addProperty(propertyName[i], propertyValue[i]);
      }
    }else
      ajaxCommand.addProperty(propertyName, propertyValue);
    
    if(pageName)
      ajaxCommand.addProperty('jb.renderBack.page', pageName);

    if(resCompId)
      ajaxCommand.addProperty('jb.renderBack.component', resCompId);
    ajaxCommand.post(function (transport)
        {
          if(resCompId)
          {
            JB.StateMachine.rerender(resCompId, transport.responseText );
            if(onComplete)
            {
              onComplete();
            }
          }
        }
    );
    return false;
  },
  
  /*
    Run a server side method argumentless. methodName must be a method of java
    object by componentId. On return, the server should try to render
    compoent resCompId
  */
  
  invoke : function(componentId, methodName, resCompId, msg, callback)
  {
    var urlStr = window.location.href;
    var ajaxCommand = new JB.AJaxCommand(urlStr, "invoke", componentId, "clientId");
    ajaxCommand.addProperty('methodName', methodName);
    if(resCompId)
      ajaxCommand.addProperty('jb.renderBack.component', resCompId);
    
    ajaxCommand.post(function (transport)
        {
          if($(resCompId))
          {
            JB.StateMachine.rerender(resCompId, transport.responseText)
            if(callback) 
                  callback();
          }
        }
    );
  },
  
   /**
     * Sets a new value to a component on the server side.
     * @method setValue
     * @param reqCompId {string} the id of the element whose value is to be set. 
     * @param newValue {string} value to be set.
     * @param resCompId {string} on return, the component to be rendered. 
    **/
  setValue : function (reqCompId, newValue, resCompId){
     var url = JBUtil.getUrl();
     
     JB.Ajax.post(url+'?editAction=change&'+JB.REQ_COMP_ID+'='+reqCompId+'&'     
        + JB.RES_COMP_ID + '=' + resCompId, newValue, 
      function (transport)
      {
        if(resCompId)
            JB.StateMachine.rerender(resCompId, transport.responseText );
        else
            log(reqCompId, 'value saved', JBDebugger.INFO);
      }
   );
  },
  //synch value with server
  synchValue: function(reqCompId, resCompId)
  {
     this.setValue(reqCompId, $(reqCompId).value, resCompId);
  },
  synchStruct: function(compId) {
    debug("start synchStruct");
    var comp = $(compId)  ;
    if(comp==null)
    {
        log("Not component found" + compId);
        return;//we do nothing if not component defined
    }
    var xml ='';//'<component id="' + comp.id + '">';
    var children = comp.childNodes;
    for(i=0;i<children.length;i++)
    {
        if(typeof(children[i].id) != 'undefined')
            xml += children[i].id+',';
    }
    //
    //this would cause the server sync up component and then reload client
    //component
    //
    
    this.raiseServerEvent("com.jb.web.bean.event.ReorderChildren", {
            componentId:compId,
            payload:xml,
            renderBack:false
        }
    );
    debug("end synchStruct");
    
  },
  
   /**
     * render a component from server.
     * @method render
     * @param urlStr {string} url to post. 
     * @param resCompId {string} on return, the component to be rendered. 
    **/
  renderChildren : function (resCompId, options)
  {
    urlStr = JBUtil.getUrl();
    if(urlStr.indexOf('?')==-1)
      urlStr = urlStr + '?';
    else
      urlStr = urlStr + '&';
    
    urlStr = urlStr + "editAction=renderChildren&"+JB.RES_COMP_ID+"="+resCompId;

    JB.Ajax.post(urlStr, '', 
      function (transport)
      {
        if($(resCompId))
        {
          JB.StateMachine.rerender(resCompId, transport.responseText);
          if(options && options.callback)
            options.callback(resCompId);
        }
      }
    );
  },
  // return innerHTML for a component
  innerHTML : function (reqCompId)
  {
    urlStr = JBUtil.getUrl()+ "?" + "editAction=renderChildren&"+JB.RES_COMP_ID+"="+reqCompId;
    return JB.Ajax.postSync(urlStr, '');
  },
  
/*
 * post a request to the server
 * @param urlStr url to post, might have parameters
 * @param resCompId component id to renderChildren as the results of post.
*/
  post : function (urlStr, resCompId)
  {
    if(urlStr.indexOf('?')==-1)
      urlStr = urlStr + '?';
    else
      urlStr = urlStr + '&';
    
    urlStr = urlStr + "editAction=processRequest&"+JB.RES_COMP_ID+"="+resCompId;
    JB.Ajax.post(urlStr, '', 
      function (transport)
      {
        if($(resCompId))
        {
          JB.StateMachine.rerender(resCompId, transport.responseText );
        }
      }
    );
  },
  
  /**
     * Synch element location to server.
     * @method synchLocation
     * @param clientId {string} the id of the element whose location to be 
     * synched.
    **/
  synchLocation : function (clientId)
  {
    ele = $(clientId);
    if(ele)
    {
      this.setDim(clientId, ele.style.left, ele.style.top, ele.style.width, ele.style.height,'moving');
    }
  },
   /**
     * Synch element site to server.
     * @method synchSize
     * @param clientId {string} the id of the element whose size to be 
     * synched.
    **/
  synchSize : function (clientId)
  {
    ele = $(clientId);
    if(ele)
    {
      this.setDim(clientId, ele.style.left, ele.style.top, ele.style.width, ele.style.height,'sizing');
    }
  },
  
   /**
     * Synch element site to server.
     * @method synchDim
     * @param clientId {string} the id of the element whose size to be 
     * synched.
    **/
  synchDim : function (clientId)
  {
    ele = $(clientId);
    if(ele)
    {
      this.setDim(clientId, ele.style.left, ele.style.top, ele.style.width, ele.style.height);
    }
  },
  
   /**
     * Synch element size and location to server.
     * @method setDim
     * @param clientId {string} the id of the element whose size to be 
     * synched.
    **/
  setDim : function (clientId, x, y, w, h, mode)
  {
    var url = window.location.href;
    var loc = url.indexOf('clientId');
    if(loc!=-1)
      url = url.substring(0, loc-1);
  
    var questionMark = url.indexOf('?');
    if(questionMark==-1)
      url = url+'?'
    else
      url = url.substring(0, questionMark)+'?';
    //ajax this
    x=escape(x);
    y=escape(y);
    w=escape(w);
    h=escape(h);
      
    if(mode==null)
      mode = 'dim';
   
    JB.Ajax.post(url
      +'clientId='+clientId
      +'&x='+x
      +'&y='+y
      +'&h='+h
      +'&w='+w
      +'&editAction=com.jb.ajax.setDim&mode='+mode,''
    );
  },
  /**
  * Shows errors
  *
  */
  showError : function()
  {
    if($('jbError'))
    {
      $('jbError').style.display='';
    }
  },

  /**
  * test whether a server action errors out
  *
  */
  hasError : function (transport)
  {
    if(transport)
    {
      var error = transport.responseText.indexOf('aJaxError, refresh')!=-1;
      if(error)
       debug(transport.responseText);
    }else
      return true;
  },
  /*
  * Sets rate on a rater component.
  *
  */
  setRate : function(clientId, rate)
  {
    this.setProperty(clientId, 'currentRate', rate, clientId); 
    return false;
  },
  /*
  * Called on end dragging
  *
  */
  onDragEnd : function(event, dragElement)
  {
      var ele = dragElement.clonedFrom?dragElement.clonedFrom:dragElement;
      var parent = JavaBase.DomUtil.getParentNode(ele);
    
      var dragged = dragElement.clonedFrom?dragElement.clonedFrom:dragElement;
      if(this.draggedOn)
      {
        var droppedOn = Element.readAttribute(this.draggedOn, 'onDroppedOn');
    
        if(droppedOn)
        {
            var _f = eval(droppedOn);
            if(_f instanceof Function)
            {
                _f(dragged, this.draggedOn);
            }
        }else {
            JBPortal.onRearrange(dragged)
        }
      }else
         JBPortal.onRearrange(dragged)
      this.dragged=null;   
  },
  
  /*
  * Called on dragging begin
  *
  */
  onDragBegin : function(event, dragElement)
  {
      this.draggedOn=null;   
      this.dragged=dragElement;   
  },
  /*
  * Called on dragging
  *
  */
  onDrag : function(event, dragElement)
  {
      debug("in onDrag");
      var ele = dragElement.clonedFrom?dragElement.clonedFrom:dragElement;
      var parent = JavaBase.DomUtil.getParentNode(ele);
      var rect =JavaBase.Dimension.getElementRect(parent);
      var childRect=JavaBase.Dimension.getElementRect(dragElement);
      
      dragElement.percent =
      {
          x: 100*(childRect.left - rect.left)/(rect.width-childRect.width),
          y: 100*(childRect.top - rect.top)/(rect.height-childRect.height)
      };
      
      ele.percent = dragElement.percent;

      var pt = JavaBase.EventFactory.getPosition(event);
      dragged = dragElement.clonedFrom?dragElement.clonedFrom:dragElement;
      
      debug(ele.percent.x);

    //on drag of the dragging element
      var drag = Element.readAttribute(dragged, 'jb_drag');
      if(drag)
      {
        _func = eval(drag);
        if(_func instanceof Function)
            _func(dragged);
      }

      //iterate through all the droppables, and perform droppable dragging functions
      for(i=0;i<JB.droppables.length;i++)
      {
        ele = $(JB.droppables[i]);
        rect1 = JavaBase.Dimension.getElementRect(ele);    
        if(JavaBase.Dimension.isInRect(rect1, pt))
        {
            if(this.draggedOn != ele)
            {
                this.draggedOn= ele;
                var draggedOn = Element.readAttribute(this.draggedOn, 'onDraggedOn');

                var _f = eval(draggedOn);
                if(_f instanceof Function)
                {
                    _f(dragged, this.draggedOn, pt);
                }
            } else {
                var dragging = Element.readAttribute(this.draggedOn, 'onJBDrag');
                _f = eval(dragging);
                if(_f instanceof Function)
                {
                    _f(dragged, this.draggedOn, pt);
                }
            }
        } else
        {
            if(this.draggedOn==ele)
            {
               var draggedOut = Element.readAttribute(this.draggedOn, 'onDraggedOut');
               _f = eval(draggedOut);
                if(_f instanceof Function)
                {
                    _f(dragged, this.draggedOn, pt);
                }
               this.draggedOn = null;
            }
        }
      }
    //  debug("out onDrag");
  },
  //hide hint
  hideHint :function ()
  {
    if($(this.dialogBoxName))
      $(this.dialogBoxName).style.display='none';
  },
  //display hint
  showHint :function (ele, hintId)
  {
    if($(hintId))
    {
      this.messageBox($(hintId).innerHTML, ele, false, 10000);
    }
  },
  //
  //creates a dialog box
  //
  /*modal:true,
        autoTabs:true,
        width:500,
        height:300,
        shadow:true,
        minWidth:300,
        minHeight:300
        */

  createDialogBox: function(title, msg, opts)
  {
      var divElm = $(this.dialogBoxName);
      if(!!divElm)
      {
          $(this.dialogBoxName+'t').innerHTML=title;
          $(this.dialogBoxName+'c').innerHTML=msg;
          return divElm;
      }

      var options = Object.extend({
            width:'200px',
            height:'120px'
        }, opts || {});
     
//       options.id=this.dialogBoxName;
       return this.createWindow(title, msg, options);
  },
  genid:0,
  //
  //create a message window
  //you can pass an id via opts.id
  //
  createWindow: function(title, msg, opts)
  {
    var options = Object.extend({
            width:'300px',
            height:'200px',
            id:'_gen'+(this.genid++)
        }, opts || {});
        //do not want to recreate a new one if there is already one exist
      if($(options.id)) {
          return $(options.id);
      }
      //create the popup window
      var divElm = document.createElement("div");
      divElm.style.display='none';
        divElm.id=options.id;
        divElm.style.height = options.height;
        divElm.style.width = options.width;
        divElm.setAttribute("draggable",'true');
        
        Element.addClassName(divElm,'jb_window');
        document.body.appendChild(divElm);

        titleDiv= document.createElement("div");
        titleDiv.id=divElm.id+'t';
        
        Element.addClassName(titleDiv,'jb_window_title');
        divElm.appendChild(titleDiv);
        contentDiv= document.createElement("div");
        contentDiv.id=divElm.id+'c';
        contentDiv.style.height = (parseInt(options.height)-50) + 'px';

        Element.addClassName(contentDiv,'jb_window_area');
        divElm.appendChild(contentDiv);
        footDiv= document.createElement("div");
        footDiv.id=divElm.id+'f';
        divElm.appendChild(footDiv);
        
        var button= document.createElement("input");
        
        button.id=divElm.id+'b';
        button.type="button";
        button.style.width="80px";
        
        button.value='Close';
        
        button.onclick= 
            function()
            {
                JBRectTool.popdown(divElm, options);
            };
        Element.addClassName(footDiv,'jb_window_foot');

        footDiv.appendChild(button);
        titleDiv.innerHTML=title;
        titleDiv.onmousedown=function(e) {
        if(window.event)
            _selector.pick(window.event, divElm.id);
        else
            _selector.pick(e, divElm.id);
      }
   
      contentDiv.innerHTML=msg;
      divElm.contentElement=contentDiv;
      divElm.titleElement=titleDiv;

      return divElm;  
  },

  //show a message box
  messageBox : function (msg,  args)
    {
      var options = Object.extend
      (
        {title:"Message Box"}
        , args||{}
        );

        var divElm = this.createDialogBox(options.title, msg, options);
        JBRectTool.popup(divElm, options);
        return divElm;
    },
    Ajax :
    {
      post: function(urlStr, newValue, onComplete, ele, waitMsg){        
        JB.hideHint();
        if($('javaBaseWaitingImg'))
        {
            $('javaBaseWaitingImg').style.display='';
        } 
        var request = new Ajax.Request(urlStr, 
          {
            onComplete : function(){              
              if(!JB.hasError(arguments[0]))
              {
                if($('javaBaseWaitingImg'))
                {
                  $('javaBaseWaitingImg').style.display='none';
                }
                if(onComplete) onComplete(arguments[0]); 
              }
            },
            asynchronous: true,
            contentType: '',
            postBody : newValue,
            method :'post'
          }
        )
      },
      //sync post and return resp string
      postSync: function(urlStr, newValue){
        resp = '';
        var request = new Ajax.Request(urlStr, 
          {
            onComplete : function(transport){
                resp = transport.responseText ;
            },
            asynchronous: false,
            contentType: '',
            postBody : newValue,
            method :'post'
          }
        );
        return resp; 
      }
    },

    AJaxCommand : function(urlStr, action, compId, idType)
    {
      this.url = urlStr;
      this.compId = compId;
      this.idType = idType;
      this.properties = [];
      this.action = action;
      this.addProperty = function(name, value)
      {
        this.properties[this.properties.length] = {name:name, value:value};
      }
    
      this.post = function(callback)
      {
        if(!this.idType)
          this.idType='id';
        var str2send = "<jbajax><id>"+this.compId+"</id>"
          +"<idType>"+this.idType+"</idType>"
          +"<action>"+this.action+"</action>";
        if(this.properties.length>0)
        {
          str2send += "<properties>";
          for(i=0;i<this.properties.length;i++)
          {
            str2send += '<property name="'+this.properties[i].name+'">'
            +"<![CDATA["+this.properties[i].value+"]]></property>"
          }
          str2send += "</properties>";
        }
          str2send += "</jbajax>";
        if(this.url.indexOf('?')==-1)
          this.url = this.url + '?';
        else
          this.url = this.url + '&';
        
        this.url = this.url + "editAction=AJaxRequest";
        //alert(str2send);
        JB.Ajax.post(this.url, str2send, callback);
      }
    }
}

JB = new JBCore();

function JBStretchBody() {
    JB.stretch(document.body);    
}

LayoutManager.addListener('stretchablePane',
    function (ele)
    {
        JBStretchBody();
    }
);


JB.Portal = Class.create();
JB.Portal.prototype = {
    initialize: function(elements, options) {
        this.div = document.createElement('div');
        this.div.id='s12312312312';
        this.div.style.border="dashed red 2px";
        this.div.style.display="block";
        this.div.style.height="200px";  
    },
    onRearrange :  function(dragged, draggedOn) 
    {
        debug("start rearrange")
        if(!dragged  || JBPortal.div.parentNode==null || !(JBPortal.div.parentNode.id)) {
            debug("end rearrange due to !dragged  || JBPortal.div.parentNode==null || !(JBPortal.div.parentNode.id)");
            return;
        }
        dragged.style.display='';
        var parent = dragged.parentNode;
        
        draggedOn = JBPortal.div.parentNode;
        draggedOn.insertBefore(dragged, JBPortal.div);
        draggedOn.removeChild(JBPortal.div);
        debug("call JB.synchStruct")
        JB.synchStruct(draggedOn.id);
        debug("end rearrange")
    },
    
    onDraggedOn :  function(dragged, draggedOn) 
    {
        if(!dragged || !draggedOn) {
            return;
        }    
        var parent = dragged.parentNode;
        if(parent.id == draggedOn.id)
            return;    
    },
    showLocation : function(dragged, draggedTo, location) {
        var rect = JavaBase.Dimension.getElementRect(dragged, true);    
        debug(' showLocation ' + rect.height + ' '+dragged.id);

        //dragged.style.height;
        if(JBPortal.div.dragging==null || JBPortal.div.dragging.id != dragged.id)
        {
            JBPortal.div.style.height=rect.height + 'px';
            JBPortal.div.style.width=dragged.style.width;
            JBPortal.div.dragging=dragged;
        }
        
        dragged.style.display='none';
        if(location!=null)
        {
            draggedTo.insertBefore(JBPortal.div, location);
        }else
            draggedTo.appendChild(JBPortal.div);
    },
    
    onDragging :  function(dragged, draggedOn, pt) 
    {
        if(!dragged || !draggedOn) {
            return;
        }
        var parent = dragged.parentNode;

        portlets = document.getElementsByClassName('portlet', draggedOn.id);
        last=0;
        debug(' onDragging ' + ' '+portlets.length);

        for(var i=0; i<portlets.length; i++){
            var rect1 = JavaBase.Dimension.getElementRect(portlets[i]);

            if(JavaBase.Dimension.isInRect(rect1, pt) ){
                JBPortal.showLocation(dragged, draggedOn, portlets[i]);
                return;
            }
            if(last<rect1.top+rect1.height)
                last=rect1.top+rect1.height;
        }
        if(pt.top>last)
        {
           JBPortal.showLocation(dragged, draggedOn, null);
        }
    }
}

JBPortal = new JB.Portal();

JB.SlideShow = Class.create();
JB.SlideShow.prototype = {
    options:null,
    div : null,
    old : null,
    pos:0,
    initialize: function(elements, options) {
        this.elements=elements;
        this.options = options;
    },
    next : function(p1, options){
        this.options= options||this.options;
        p1=$(p1);
        if(this.pos >= this.elements.length)
            this.pos=0;
       
        if(!this.div)
        {
            this.div = document.createElement('div');
            this.div.id=p1.id+'po';
            this.div.style.width=p1.style.width;
            this.div.style.height=p1.style.height;

            this.old = document.createElement('div');
            this.old.id=p1.id+'old';
            this.old.style.width=p1.style.width;
            this.old.style.height=p1.style.height;
           // this.slider=document.createElement('table');
            
            p1.innerHTML='';
            p1.appendChild(this.div);
            p1.appendChild(this.old);
        }
        
        if(this.options && this.options.effect)
        {
            this.old.innerHTML=this.div.innerHTML;
            this.div.style.display="none";
            this.div.innerHTML = JB.innerHTML(this.elements[this.pos]);
            
            if(this.options.effect=='SlideRight')
            {
                Effect.SlideRight(this.div,this.options);
            }else if(this.options.effect=='Appear')
                Effect.Appear(this.div,this.options);
            else if(this.options.effect=='SlideDown')
                Effect.SlideDown(this.div,this.options);   
            else 
                Effect.SlideRight(this.div,this.options);
        }else
            p1.innerHTML = JB.innerHTML(this.elements[this.pos]);
            
        this.pos++;
    }
}

JB.DataRecord={
  edit : function(url, reqId, repId, msg, title){
    JB._e(url+'&mode=updateDBRecord', reqId, 'com.sb.web.rss.event.CalendarEH.onProjectEvent', repId, msg,
      function ()
      {  
        if($('editTitleCell'))
          $('editTitleCell').innerHTML=title;
          
        JBUtil.showDialogBox(repId, true);
         
      }
    );
    return false;
  },
  create : function(url, reqId, repId, msg, title){
    JB._e(url+'&mode=insertDBRecord', reqId, 'com.sb.web.rss.event.CalendarEH.onProjectEvent', repId, msg,
      function ()
      {
      
        if($('editTitleCell'))
          $('editTitleCell').innerHTML=title;
        JBUtil.showDialogBox(repId, true);
       
      }
    );
    return false;
  }
}

JB.Tree = {
  toggleNode : function(url, clientId, parentId)
  {
      
     JB.raiseEvent('com.jb.web.bean.event.TreeNodeEventHandler.onToggle',
        { 
            componentId : clientId,
            renderedId : parentId,
            callback : function()
            {
                return JB.Tree.onSelect(parentId);
            }
        }
    );
  },
  
  onSelect : function(nodeId)
  {
    try
    {
        nodeSelected = $(nodeId);    
        if(nodeSelected)
        {
            var onSelectNode = Element.readAttribute(nodeId, 'onSelect'); 
            if(onSelectNode)
                eval(onSelectNode);
        }
        return true;
    }catch(e)
    {
        log(nodeId, e.message, JBDebugger.EXCEPTION); 
        return false;
    }
  },
  
  selectNode : function(e, url, clientId, parentId)
  {
     JB.raiseEvent('com.jb.web.bean.event.TreeNodeEventHandler.onSelect',
        { 
            componentId : clientId,
            renderedId : parentId,
            callback : function()
                {
                    return JB.Tree.onSelect(parentId);
                }
        }
    );
    //must be done after parent is rendered
     if(url.indexOf('http')!=-1)
      JBUtil.gotoUrl(url);
  }
}

JB.Accordion = Class.create();
JB.Accordion.prototype = {
    initialize: function(element) {
    //
    },
    touch : function (compId, set, direction)
    {
        if($(compId).style.display!='none')
            return;
        var ele2Hide=null;
        for(i=0; i<set.length;i++)
        {
            if($(set[i]) && $(set[i]).style.display!='none')
            {
                if(ele2Hide!=null) {
                    //error
                    JB.setProperty(ele2Hide.id,'displayStyle','none');
                    Element.toggle(ele2Hide.id);
                }
                ele2Hide = $(set[i]);
            }
        }
        if(ele2Hide)
        {
            Effect.BlindUp(ele2Hide,{duration:0.3,transition: Effect.Transitions.linear});
        }        
        Effect.BlindDown(compId,{duration:0.3,transition: Effect.Transitions.linear});
        //sync server side status
        if(ele2Hide)
        {
           JB.setProperty(ele2Hide.id,'displayStyle','none');
        }

        JB.setProperty(compId,'displayStyle','block');
    }    
}

Accordion = new JB.Accordion();

JB.Form =
{
    toggleCheckboxes : function(parentForm, checkPrefix, checked)
    {
        parentForm = $(parentForm);
        var eles = parentForm.elements;
         
        for(i=0; i<eles.length;i++)
        {
            if(eles[i].type =='checkbox')
            {
                if(eles[i].id.indexOf(checkPrefix)!=-1)
                {
                    eles[i].checked=checked;
                }
            }
        }
    }, 
    submit :function(formCompId, reqCompId, onComplete)
    {
      formId='f'+formCompId;
      url = $(formId).action;
      url = url+ '&editAction=processRequest&' + JB.REQ_COMP_ID 
        + '=' + formCompId + '&' + JB.RES_COMP_ID+'='+reqCompId;   
    
      url = url+ '&'+Form.serialize(formId);
    
      JB.Ajax.post(url, '', 
        function (transport)
        {
          try
          {
            JB.StateMachine.rerender(reqCompId, transport.responseText);
          }catch( e)
          {
            log(reqCompId, e.message, JBDebugger.EXCEPTION); 
          }
        }, null, null
      );
   }
};

JB.Debugger = Class.create();
var JB_DEBUG_MODE=false;
var JB_DEBUG_LEVEL=0;

JB.Debugger.prototype=
{
    INFO : -1,
    DEBUG: 0,
    WARNING : 1,
    ERROR:2,
    EXCEPTION:3,
    
    messageBox:null,
    maxCount : 50,//max number of messages to keep
    initialize: function(displayElement, options) {
        if(displayElement==null)
        {   
            displayElement = document.createElement("div");
            displayElement.style.height="200px";
            displayElement.id="jbDebugger";  
        }
        this.element=displayElement;
        this.options = options;
    },
    
    clear : function() {
        this.element.innerHTML="";
        this.render();
      //  Element.hide(this.messageBox);
    },
    
    log : function (source, message, level) {
        if(!JB_DEBUG_MODE)
            return;
        
        if(!level) {
            level=0;
        }
        if(level>=JB_DEBUG_LEVEL)
        {
            var msgChild = document.createElement("div");
            this.element.insertBefore(msgChild, this.element.firstChild);
            if(this.element.childNodes[this.maxCount-1])
            {
                this.element.removeChild(this.element.childNodes[this.maxCount-1]);
            }
            msgChild.innerHTML= jbTimer.getTime() +' - ' +source + ":"+ message ;
            if(this.messageBox!=null)
                msgChild.innerHTML=msgChild.innerHTML ;//+ this.messageBox.style.top;
            this.render();
        }
    },
    createBox:function() {
        var options = Object.extend
          (
            {title:"Debug Window", shadow:false, height:"200px", id:'debugBox'}
            , {}
          );
          this.messageBox = JB.createWindow(options.title, this.element.innerHTML, options);
          
          button= document.createElement("input");
          button.id='debugBoxClear';
          button.type="button";
          button.style.width="80px";
        
          button.value='Clear';
        
          button.onclick= function()
          {
             JBDebugger.clear();
          } 
          
          $('debugBoxf').insertBefore(button,$('debugBoxb'));
    },
    render : function() {
        if(this.messageBox==null) {
            this.createBox();
        }else {
            $(this.messageBox.id+'c').innerHTML=this.element.innerHTML;
        }
        
        Element.show(this.messageBox);
    },
    toggleDebug: function() {
        JB_DEBUG_MODE=!JB_DEBUG_MODE;
        if(!JB_DEBUG_MODE && this.messageBox!=null) {
            Element.hide(this.messageBox);
        }
    }
}

JBDebugger = new JB.Debugger(null);

function log(element, msg, level) {
    JBDebugger.log(element, msg, level);
}

function debug(msg) {
    log('debug', msg, JBDebugger.DEBUG);
}


JB.RectTool = Class.create();
JB.RectTool.prototype=
{
    initialize: function(elements, options) {
        this.elements=elements;
        this.options = options;
    },

   popdown : function (ele, opts)
   {
        var element =$(ele);

        var options = Object.extend(
            element.popupOptions?element.popupOptions:{}
        , opts || {});

        var button=options?(options.source?options.source:element.popupFrom):element.popupFrom;

        if(!button)
            button=ele;

        rect = JavaBase.Dimension.getElementRect(button,true);
        rect1 = JavaBase.Dimension.getElementRect(element, true);
        rect12 = JavaBase.Dimension.getWindowRect();

        x = 100*rect1.width/rect.width;
        y = 100*rect1.height/rect.height;
        
        rect1.left = (rect12.width - rect1.width)/2 - rect.left;
        rect1.top = (rect12.height - rect1.height)*0.33 - rect.top;
        //allowing options on location
        if(options.top)
            rect1.top = options.top;            
        if(options.left)
            rect1.left = options.left;
        
        oldInnerHTML=element.innerHTML;
        
        element.jbtool=this;
        var cloned = element.cloneNode(true);
        //set its client id
        cloned.id=element.id+'cloned';
        //add to body
        document.body.appendChild(cloned);
        //hold reference to the original
        cloned.clonedFrom=element;      
        element.popupOptions=options;
        //reassign element
        element=cloned;
        //reference for internal use
        element.popupOptions=options;
        //var oldInnerHTML=element.innerHTML;
        element.jbtool=this;
        new Effect.Parallel(
        [
            new Effect.Opacity(element, { sync: true, to: 0.5, from: 0.1 }),
            new Effect.Scale(element, 0, {
                scaleMode: { originalHeight: rect1.height, originalWidth: rect1.width }, 
                sync: true, 
                scaleFrom: 100,
                scaleTo: 5, //finishing box
                restoreAfterFinish: false}),
            
            new Effect.Move(element, { x: -rect1.left, y: -rect1.top, sync: true })
            
        ], Object.extend({            
                beforeStartInternal: function(effect) {
                   effect.effects[0].element.makePositioned().makeClipping(); 
                    //hide current 
                   element.clonedFrom.hide();
                   element.style.display="block";   
                   element.innerHTML='';
                   element.jbtool.hideShadow(cloned.clonedFrom);
                },
                afterFinishInternal: function(effect) {
                    element.style.display="none";  
                    document.body.removeChild(element);
                    LayoutManager.removeListener(element)
                    JBUtil.hideGT();
                }
            },options)
        );
   },
   
    location : function (element)
    {
        if(!element || element.style.display=='none')
            return;
        
        this.hideShadow(element);
        if(element && element.popupOptions && element.popupOptions.top)
        {
            Element.hide(element);
            return;
        }
        if(element && element.popupOptions && element.popupOptions.left)
        {
            Element.hide(element);
            return;
        }

        rect1 = JavaBase.Dimension.getElementRect(element, true);
        rect12 = JavaBase.Dimension.getWindowRect();
        rect1.left = (rect12.width - rect1.width)/2;
        rect1.top = (rect12.height - rect1.height)*0.33;

        element.style.left=rect1.left + 'px';
        element.style.top=rect1.top + 'px';
        this.shadowDiv(element);               
    },
   
   popupJob:null,
   toggle : function(element, options) {
       var ele = $(element);
       if(ele.style.display!='none')
            this.popup(ele, options)
        else
            this.popdown(ele, options);
   },

   popup : function (ele, options)
    {
        var element =$(ele);

        if(element && element.style.display!='none')
        {
            debug(element, 'either element not exist, or it is already showing');
            return;
        }
        if(this.popupJob) {
            return false;
        }
        this.popupJob=true;
        element.hide();

        source = options.source?options.source:ele;
        var button=$(source);
        //hold reference for popupfrom so can be popdown if needed
        element.popupFrom=options.source;
        element.popupOptions=options;

        if(!button)
            button = element;

        var rect = JavaBase.Dimension.getElementRect(button);
        var rect1 = JavaBase.Dimension.getElementRect(element);
        
        var rect12 = JavaBase.Dimension.getWindowRect();

        var x = 100*rect1.width/rect.width;
        var y = 100*rect1.height/rect.height;
        
        var style = element.style;
        style.left=rect.left + 'px';
        style.top=rect.top + 'px';
        style.width=rect.width+'px';
        style.height=rect.height+'px';
        style.position="absolute";

        rect1.left = (rect12.width - rect1.width)/2 - rect.left;
        rect1.top = (rect12.height - rect1.height)*0.33 - rect.top;

        if(options.top)
            rect1.top = options.top;            
        if(options.left)
            rect1.left = options.left;

        //create cloned element for animation
        var cloned = element.cloneNode(true);

        //set its client id
        cloned.id=element.id+'cloned';
        //add to body
        document.body.appendChild(cloned);
        //hold reference to the original
        cloned.clonedFrom=element;      
        //reassign element
        element=cloned;

        //var oldInnerHTML=element.innerHTML;
        cloned.clonedFrom.jbtool=this;
        
        new Effect.Parallel(
        [   new Effect.Opacity(element, { sync: true, to: 0.5, from: 0.1 }),
            new Effect.Scale(element, 100, {
                scaleMode: { originalHeight: rect1.height, originalWidth: rect1.width }, 
                sync: true, 
                scaleFrom: window.opera ? 1 : 5, //finishing box
                restoreAfterFinish: false}
                ),
            new Effect.Move(element, { x: rect1.left, y: rect1.top, sync: true })
        ], Object.extend({            
                beforeStartInternal: function(effect) {
                   effect.effects[0].element.makePositioned().makeClipping(); 
                   element.style.display="block"; 
                   element.innerHTML='';
                   element.oldzindex=element.style.zIndex;
                   element.style.zIndex=1001;
                   if(effect.options.modal)
                        JBUtil.showGT(effect.options.gtColor ? effect.options.gtColor:'#eee');
                },
                afterFinishInternal: function(effect) {
                    element.style.fontSize='';
                    var orig = element.clonedFrom;
                  
                    new Effect.Opacity(element,1);
                    
                    LayoutManager.addListener(orig,
                        function (ele1)
                        {
                            ele1.jbtool.location(ele1);
                        });
                    
                    document.body.removeChild(element);
                    orig.jbtool.popupJob=false;
                    //setting location
                    orig.style.left = element.style.left;
                    orig.style.top = element.style.top;
                    orig.style.width = element.style.width;
                    orig.style.height = element.style.height;
                    //show the orginal
                    orig.show();
                    if(effect.options.shadow)
                        orig.jbtool.shadowDiv(orig.id);               
                    orig.style.zIndex=1001;
                    //remove the cloned element
                }
            }, options)
        );
    },
    //hide shadow for an element
    hideShadow : function (element)
    {
        if(element && $(element).shadow)
            Element.hide($(element).shadow);
        else
            if($('jb_shadow'))
                Element.hide($('jb_shadow'));
    },
        //create a shadow for an element
    shadowDiv : function (divEle)
    {
        var element = $(divEle);
        var sid=element.id+'_s';
        var jbShadow = $(sid);
        if(!jbShadow)
        {
            shadowInner=
                '   <div id="'+sid+'_t" class="xst">' +
                '       <div class="xstl"></div><div id=\"'+sid+'_tm" class="xstc" style="width:261px;"></div><div class="xstr"></div>' +
                '   </div>' +
                '   <div id="'+sid+'_m" class="xsc" style="height: 86px;">' +
                '       <div class="xsml"></div><div class="xsmc" id="'+sid+'_mm" style="width:261px;"></div><div class="xsmr"></div>' +
                '   </div>' +
                '   <div id="'+sid+'_b" class="xsb">' +
                '        <div class="xsbl"></div><div class="xsbc" id="'+sid+'_bm" style="width:261px;"></div><div class="xsbr"></div>' +
                '    </div>';
            jbShadow=document.createElement("div");
            jbShadow.id=sid;
            jbShadow.className="jb_shadow";
         
            jbShadow.style.zIndex="0";
            if(element.style.zIndex)
                jbShadow.style.zIndex=parseInt(element.style.zIndex)-1;
            else
                element.style.zIndex="10";
           
            jbShadow.style.display="none";
            
            jbShadow.innerHTML=shadowInner;
            document.body.appendChild(jbShadow);//, document.body.firstChild);
        }
        element.shadow = jbShadow;   
        var rect = JavaBase.Dimension.getElementRect(divEle, true);
         
        $(sid+"_tm").style.width=rect.width+'px';
        $(sid+"_tm").style.visibility='hidden';
        $(sid+"_mm").style.width=rect.width+'px';
        $(sid+"_bm").style.width=rect.width+'px';
       
        $(sid+"_m").style.height=(rect.height-9)+'px';
        
        var style = jbShadow.style;
        
        style.left=(rect.left-6)+'px';
        style.top=(rect.top+3)+'px';
        style.height=(rect.height+3)+'px';
        style.width=(rect.width+12)+'px';
        style.display="block"
    }
}

JBRectTool = new JB.RectTool();//global

JB.MapTool = 
{
    geocoder : null,
    loaded:false,
    makeIcon : function(options)
    {
    	var baseIcon = new GIcon();
        baseIcon.shadow = options.shadowImage;
        baseIcon.iconSize = new GSize(32, 32);
        baseIcon.shadowSize = new GSize(37, 34);
        baseIcon.iconAnchor = new GPoint(9, 34);
        baseIcon.infoWindowAnchor = new GPoint(9, 2);
        baseIcon.infoShadowAnchor = new GPoint(18, 25);
        return baseIcon;
    },
    
    createMarker :function (point, options) {
        if(options.iconImage)
        {
            var icon = new GIcon(this.makeIcon(options));
            icon.image = options.iconImage;
            var marker = new GMarker(point, icon);
            return marker;
        }else
            return new GMarker(point);
        
    },
    addMarkers : function (map, point, options, sequence) {
        if(!this.testService()) {
            return;
        }
        //create a marker
        var marker = this.createMarker(point, options);
        //add listener
        GEvent.addListener(marker, "click", 
            function() {    
              var ele=options.infoWindow;
              var oId = sequence;
              var listId=options.listId;
              if($(ele))
              {
                if(listId!=null && listId!='null')
                {
                    JB.setProperty(listId, 'selected', sequence, ele, 
                        function()
                        {
                            var cloned = $(ele).cloneNode(true);
                            cloned.id=$(ele).id + 'cloned';
                            cloned.style.display="";
                            marker.openInfoWindow(cloned);
                        });
              }else {
                    var cloned = $(ele).cloneNode(true);
                    cloned.id=$(ele).id + 'cloned';
                    cloned.style.display="";
                    marker.openInfoWindow(cloned);
              }
            }
            }
          );          
          //overlay the marker
          map.addOverlay(marker);
    },
    getDecoder : function() {
        if(this.geoDecoder==null)
            this.geoDecoder = new GClientGeocoder();        
        
        return this.geoDecoder;
        
    },
    testService : function() {
        try
        {
            if (GBrowserIsCompatible =='undefined') 
            {
                alert("Google is not available");
                return false;
            }else
                return true;
        }catch (e) {
            return false;
        }
    },
    init : function (ele, options) {
        if(!this.testService()) {
            return null;
        }
        if (GBrowserIsCompatible()) 
        {
            var map = $(ele).map;
            if(map==null)
            {
                map = new GMap2($(ele));
                $(ele).map=map;
            }
 
           if(options && options.mapControl)
            {
                if(options.mapControl=='Small')
                    map.addControl(new GSmallMapControl());
                else if(options.mapControl=='Large')
                    map.addControl(new GLargeMapControl());
            }
           

            if(options && options.typeControl)
                map.addControl(new GMapTypeControl());

            if(options && options.overviewControl)
            {
                map.addControl(new GOverviewMapControl(new GSize(200,160)));
            }

          //  if(options && options.hierarchicalTypeControl)
          //      map.addControl(new GHierarchicalMapTypeControl());
        
            return map;
        }
        return null;
    },

    load : function (ele, x, y, options) {
        var map = this.init(ele, options);
        if(map==null)
            return map;
        map.setCenter(new GLatLng(x, y), options.scale==0?10:options.scale);
        this.addMarkers(map, new GLatLng(x, y), options, 0);
        return map;
    },

    loadJSON : function(ele, divs, options) {
        var map = this.init(ele, options);
        if(map==null)
            return map;

        var addresses = divs.addresses;
        for(i=0; i<addresses.length; i++)
        {
            var pt = this.getLocation(addresses[i], map, options, i);
            if(pt!=null)
            {
                if(i==0)
                    map.setCenter(pt, options.scale==0?10:options.scale);
                this.addMarkers(map, pt, options, i);
            }
        }
    },
    
    getLocation : function(address, map, options, i) {
        if(''+address.latitude != 'undefined')
        {
           return new GLatLng(address.latitude, address.longitude);
        }else if(address.address!=null)
        {
            this.getDecoder().getLatLng(address.address,
                function(point) {
                    if(i==0)
                        map.setCenter(point, options.scale==0?10:options.scale);
                    JB.MapTool.addMarkers(map, point, options, i);
                }
            );
            return NULL;
        }else {
            response = this.getGeoDecoder().getLatLng(address);
            place = response.Placemark[0];    
            point = new GLatLng(place.Point.coordinates[1], place.Point.coordinates[0]);
            return point;
        }
    },
    
    setLocation : function(address, ele, options)
    {
        var map = this.init(ele, options);
        if(map==null)
            return map;
        this.getDecoder().getLatLng(
          address,
          function(point) {
            if (!point) {
              alert(address + " not found");
            } else {
              map.setCenter(point, 13);
              var marker = new GMarker(point);
              map.addOverlay(marker);
              if(options && options.message)
                marker.openInfoWindowHtml(options.message);
            }
          }
        );
    }    
}

JB.Shuttle = Class.create();

JB.Shuttle.prototype = {
    shuttle : null,
    field : null,
    left : null,
    right : null,
    
    initialize: function(element) {
        this.shuttle = $(element);
        this.field = $(element+'f');
        this.left = $(element+'left');
        this.right = $(element+'right');
    },
    up : function (field)
    {
        var toElement = $(field+'right');  
        var options = toElement.options;
        var len = options.length;
        for(i=1;i<len;i++){
          var option = options[i];
          if(option.selected)
          {
            next = options[i-1];
            toElement.insertBefore(option, next);
         }
        }
        this.updateField(field);
    },  
    down : function ( field)
    {
        var toElement = $(field+'right');      
        var options = toElement.options;
        var len = options.length;
        for(i=len-2;i>-1;i--){
          var option = options[i];
          if(option.selected)
          {
            next = options[i+2];
            toElement.insertBefore(option, next);
          }
        }
        this.updateField(field);
    }, 
    updateField : function(field) {
       if(field) {
          selectField = $(field+'f');
          len = selectField.options.length;
          for(i=len-1;i>-1;i--){
              option = selectField.options.item(i);
              selectField.removeChild(option);
          }
          selected = $(field+'right');
          len = selected.options.length;
          for(i=0;i<len;i++){
            option = selected.options.item(i);
            o = option.cloneNode(true);
            o.selected = true;
            selectField.appendChild(o);
          }
       }
    },
    moveOptions : function (from, to, field)
    {
        var fromElement = $(from);
        var toElement = $(to);
        var len = fromElement.options.length;
    
        for(i=len-1;i>-1;i--){
          var option = fromElement.options.item(i);
          if(option.selected)
          {
            fromElement.options[i]=null;
            option.selected=false;
            toElement.options.add(option);
          }
        }
        this.updateField(field);
    }  
};

JBShuttle=new JB.Shuttle();
JB.Photo={
  onChangeRect : function (e, dragElement)
  {
    var rect = JavaBase.Dimension.getInnerElementRect(dragElement);
    var bigRect = JavaBase.Dimension.getInnerElementRect(JB.Photo.selectElement);
    
    var style = $("leftd").style;
     
    style.left = '0px';
    style.top = "0px";
    style.height = bigRect.height+'px';
    style.width=rect.left + 'px';
    style.display='';
     
    style = $("rightd").style;
  
    style.left = rect.left+rect.width + 'px';
    style.top = "0px";
    style.height = bigRect.height+'px';
    style.width=(bigRect.width - rect.left - rect.width) + 'px';
    style.display='';
    
   // window.status=rect.top;
    style = $("topd").style;
  
    style.left = rect.left + 'px';
    style.top = "0px";
    style.height = rect.top+'px';
    style.width = rect.width+'px';
    style.fontSize='0px';
    style.borderWidth="0px";
    style.display='';
  
    style = $("bottomd").style;  
    style.left = rect.left + 'px';
    style.top = rect.top+rect.height + "px";
    style.height = (bigRect.height - rect.top - rect.height)+'px';
    style.width = rect.width+'px';
    style.fontSize='0px';
    style.borderWidth="0px";
    style.display='';
    
  },
  unselect : function(e)
  {
    if(this.selectElement)
    {
      this.selectElement.removeChild(this.leftd);
      this.selectElement.removeChild(this.rightd);
      this.selectElement.removeChild(this.topd);
      this.selectElement.removeChild(this.bottomd);
      this.selectElement.removeChild(this.centerd);
      this.leftd=null;
      this.topd=null;
      this.bottomd=null;
      this.rightd=null;
      this.centerd=null;
      this.selectElement=null;
    }
  },
  
  select: function (e, divEle)
  {
    if(this.selectElement)
      return;
    this.selectElement= divEle;
    this.leftd = document.createElement('div');
    this.leftd.id = "leftd";

    this.topd = document.createElement('div');
    this.topd.id = "topd";

    this.bottomd = document.createElement('div');
    this.bottomd.id = "bottomd";
  
    this.rightd = document.createElement('div');
    this.rightd.id = "rightd";
  
    this.centerd = document.createElement('div');
    this.centerd.id = "centerd";
    
    var style = this.centerd.style;
    
    style.position = 'absolute';
    style.filter =  "alpha(opacity=3)";
    style.opacity = 0.03;
    style.left='10px';
    style.top='10px';
    style.width="200px";
    style.height="300px";
    style.zIndex = 120;
    style.backgroundColor="white";
     
    style = this.leftd.style;
    
    style.position = 'absolute';
    style.filter =  "alpha(opacity=30)";
    style.opacity = 0.3;
    style.width="20px";
    style.height="30px";
    style.zIndex = 100;
    style.backgroundColor="blue";
    style.display = 'none';
    
    style = this.topd.style; 
    style.position = 'absolute';
    style.filter =  "alpha(opacity=30)";
    style.opacity = 0.3;
    style.width="20px";
    style.height="30px";
    style.zIndex = 100;
    style.backgroundColor="blue";
    style.display = 'none';
     
     
    style = this.rightd.style;
    style.position = 'absolute';
    style.filter =  "alpha(opacity=30)";
    style.opacity = 0.3;
    style.width="20px";
    style.height="30px";
    style.zIndex = 100;
    style.backgroundColor="blue";
    style.display = 'none';
     
    style = this.bottomd.style;
    style.position = 'absolute';
    style.opacity = 0.3;
    style.filter = "alpha(opacity=30)";
    style.backgroundColor="blue";
    style.width="20px";
    style.height="30px";
    style.zIndex = 100;
    style.display = 'none';

    JavaBase.DomUtil.setAttributeValue(this.centerd, "draggable", "true");
    JavaBase.DomUtil.setAttributeValue(this.centerd, "onDrag_Drag", "JB.Photo.onChangeRect");
    JavaBase.DomUtil.setAttributeValue(this.centerd, "onResize", "JB.Photo.onChangeRect");
    JavaBase.DomUtil.setAttributeValue(this.centerd, "dragBox", divEle.id);
    JavaBase.DomUtil.setAttributeValue(this.centerd, "resizable", "true");
    
    divEle.style.position="absolute";
    divEle.appendChild(this.centerd);
    divEle.appendChild(this.leftd);
    divEle.appendChild(this.topd);
    divEle.appendChild(this.bottomd);
    divEle.appendChild(this.rightd);
    this.onChangeRect(e, this.centerd);
  },
  snapIt : function ()
  {
    rect = JavaBase.Dimension.getInnerElementRect(this.centerd);
    url =  JBUtil.getUrl() + "?"
      +"left="+(rect.left)
      +"&top="+(rect.top)
      +"&width="+ (rect.width )
      +"&height="+ (rect.height );
  },
  snap : function (url, box, img, comp)
  {
    var urlStr = url;
    if(url.indexOf("?")==-1)
      url = url+'?';
    else
      url = url+'&';
    boxRect = JavaBase.Dimension.getElementRect(box);
    imgRect = JavaBase.Dimension.getElementRect(img);    
    url = url
      +"left="+(boxRect.left-imgRect.left)
      +"&top="+(boxRect.top-imgRect.top)
      +"&width="+ boxRect.width
      +"&height="+ boxRect.height;    
    JBUtil.gotoUrl(url);
  },
  loadImage: function(src, img, ele, eventEle)
  {
    this.eventEle = eventEle;
    $(img).src='resources/images/clipart/category/indicator.gif';
    var update = new Ajax.Updater(ele, src);
    var imgd= new Image( );
    imgd.src = src;
    executer = new PeriodicalExecuter(
        function(p1)
        {
            if(imgd.complete)
            {
                $(img).src=src;
                $(ele).style.width = imgd.width+'px';
                $(ele).style.height = imgd.height+'px';
                JBRectTool.popup(ele, {modal:true,source:eventEle, gtColor:'#eee',shadow:true});
                p1.stop();
            }
     }, 0.5); 
  }
}
//Editors
JB.DateEditor = Class.create();
JB.DateEditor.prototype = {
    initialize: function(tid) {
        this.id = tid;
        this.editor = document.createElement("div");
        var _e = this.editor;
        var eid=this.id + "df";
        this.dateE = document.createElement("input");
        this.dateE.type="text";
        this.dateE.name=eid;
        this.dateE.id=eid;
        _e.appendChild(this.dateE);
        Element.addClassName(this.dateE,"jb_cell_editor");
        Element.addClassName(this.dateE,"jb_cell");
        
        this.dateI = document.createElement("img");
        this.dateI.src = "resources/images/palette/cal.gif";
        this.dateI.id=eid+"PIPos";
        this.dateI.name=eid+"PIPos";
        this.dateI.border="0px";
        this.dateI.style.width="14px";
        this.dateI.style.marginLeft="2px";
        this.dateI.align="absmiddle";

        Event.observe(this.dateE,'keypress', function(evt){
            var charCode = (evt.charCode) ? evt.charCode :
                   ((evt.keyCode) ? evt.keyCode :
                   ((evt.which) ? evt.which : 0));
                   
            if (charCode == Event.KEY_RETURN) 
            {
                var element = Event.element(evt);
                cell = element.cell;
                var p = element.parentNode;
                if(cell.innerHTML!=element.value)
                {
                    cell.innerHTML=element.value;
                    p.editor.setValue(cell, element.value);
                    Element.addClassName(cell, "jb_cell_changed");
                }
                p.hide();
            }
         });
         
         Element.observe(this.dateI, 'mouseup', function(evt){
            toggleDatePicker(eid+'PI',eid);
         });
        _e.appendChild(this.dateI);
        _e.id = this.id+'de';
        _e.style.position="absolute";
        _e.style.top="100px";
        _e.style.left="200px";
        _e.style.width="200px";
        _e.style.display="none";
        _e.style.zIndex="100";
        _e.editor = this;
        document.body.appendChild(_e);
    },
    setValue : function(cell, newValue) {
       if(this.onSetValue)
          this.onSetValue(cell, newValue);
    },
    show : function(ele) {
        var _e = this.editor;
        content=$(ele+'_c');
        eleWidth = parseInt(content.style.width);
        
        isFirst = Element.hasClassName(content,'jb_cell_inner_first');
        _e.style.width=eleWidth+'px';        
        this.dateE.style.width=(eleWidth-22)+'px';
        cPosition = Position.cumulativeOffset(content);
        realPosition = Position.realOffset(content);
        _e.style.top=(cPosition[1]-realPosition[1]-1)+'px';
        _e.style.left=(cPosition[0]-realPosition[0] - (isFirst?-1:0)) +'px';
        _e.style.display='block';
        //jb_cell_inner_first
        this.dateE.value=content.innerHTML;
        this.dateE.cell= content;
        Form.Element.focus(this.dateE);
    },
    hide : function(ele) {
        element = this.dateE;
        cell = element.cell;
        var p = element.parentNode;
        if(cell.innerHTML!=element.value)
        {
            cell.innerHTML=element.value;  
            p.editor.setValue(cell, element.value);
            Element.addClassName(cell, "jb_cell_changed");
        }
        this.editor.hide();
    }    
}
JB.TextEditor = Class.create();

JB.TextEditor.prototype = {
    initialize:function(id)
    {
        this.id = id;
        log(id, 'initialize editor', JBDebugger.INFO);
        this.editor = document.createElement("input");
        var _e = this.editor;
        document.body.appendChild(_e);
        _e.id = this.id+'editor';
        _e.style.position="absolute";
        _e.style.top="100px";
        _e.style.left="200px";
        _e.style.width="200px";
        _e.style.display="none";
        _e.style.zIndex="100";
        _e.editor = this;
        Element.addClassName(_e,"jb_cell_editor");
        Element.addClassName(_e,"jb_cell");
        Event.observe(_e,'keypress', function(evt){
            var charCode = (evt.charCode) ? evt.charCode :
                   ((evt.keyCode) ? evt.keyCode :
                   ((evt.which) ? evt.which : 0));
                   
            if (charCode == Event.KEY_RETURN) 
            {
                var element = Event.element(evt);
                cell = element.cell;
                if(cell.innerHTML!=element.value)
                {
                    cell.innerHTML=element.value;  
                    element.editor.setValue(cell, element.value);
                    Element.addClassName(cell, "jb_cell_changed");
                }
                element.hide();
            }
         });
    },
    setValue : function(cell, newValue) {
       if(this.onSetValue)
          this.onSetValue(cell, newValue);
    },
    show:function(ele) {
        log(ele, 'show editor', JBDebugger.INFO);
        content=$(ele+'_c');
        this.currentElement=ele;
        var _e = this.editor;
       // log(ele.id);
        isFirst = Element.hasClassName(content,'jb_cell_inner_first');

        _e.style.width=(parseInt(content.style.width))+'px';        
        
        cPosition = Position.cumulativeOffset(content);
        realPosition = Position.realOffset(content);
        
        _e.style.top=(cPosition[1]-realPosition[1])+'px';
        _e.style.left=(cPosition[0]-realPosition[0]+(isFirst?1:0)) +'px';
        _e.style.display='block';
        _e.value=content.innerHTML;
        _e.cell= content;

        Form.Element.focus(_e);
    },
    hide : function(ele) {
         this.editor.hide();
    }
}

JB.LovEditor = Class.create();
JB.LovEditor.prototype = {
    initialize:function(id)
    {
        this.id = id;
        log(id, 'initialize editor', JBDebugger.INFO);
        this.editor = document.createElement("select");
        var _e = this.editor;
        document.body.appendChild(_e);
        _e.id = this.id+'editor';
        _e.style.position="absolute";
        _e.style.top="100px";
        _e.style.left="200px";
        _e.style.width="200px";
        _e.style.display="none";
        _e.style.zIndex="100";
        _e.editor = this;
        Element.addClassName(_e,"jb_cell_editor");
        Element.addClassName(_e,"jb_cell");
    },
    setValue : function(cell, newValue) {
       if(this.onSetValue)
          this.onSetValue(cell, newValue);
    },
    show:function(ele) {
        log(ele, 'show editor', JBDebugger.INFO);
        content=$(ele+'_c');
        this.currentElement=$(ele);
        var lov = $(this.currentElement.column.id+'_lov');
        var _e = this.editor;
        _e.options.length = 0;
	for(i=0;i<lov.options.length;i++)
	{
            _e.options[i] = new Option(lov.options[i].innerHTML, lov.options[i].value);
	}
        //setup the location and position
        _e.style.width=(parseInt(content.style.width))+'px';        
        
        cPosition = Position.cumulativeOffset(content);
        realPosition = Position.realOffset(content);
        
        _e.style.top=(cPosition[1]-realPosition[1]-1)+'px';
        _e.style.left=(cPosition[0]-realPosition[0]-1) +'px';
        _e.style.display='block';
        _e.value=content.innerHTML;
        _e.orgValue=content.innerHTML;
        _e.cell= content;
        Form.Element.focus(_e);
    },
    
    hide : function(ele) {
        element = this.editor;
        cell = element.cell;
        if(element.orgValue!=element.value)
        {
            cell.innerHTML=element.value;
            element.editor.setValue(cell, element.value);
            Element.addClassName(cell, "jb_cell_changed");
        }
        element.hide();
    }
}


//------------------------------------------------------------------
//Table Implementation
//
//TODO sorting
//TODO editing
//TODO context menu
//

JB.Table = Class.create();

JB.Table.prototype = {
   // rows: new Array(),
    selectedRow : null,
    currentColumn : null,
    scrollLeft:0,
    anchorX:0,
    origWidth:0,
    elements:null,
    rows:null,
    innerWidth:0,
    editor:null,
    dateEditor:null,
    selectMode:'row',
    cells : null,
    initialize: function(tid) {
        this.id = tid;
        this.selectMode = Element.readAttribute(tid, 'jb_select_mode');
        this.editable = 'true' == Element.readAttribute(tid, 'editable');
        if(!(!this.selectMode) && this.editable)
            this.selectMode='cell';
            
        var headers = document.getElementsByClassName('jb_hd_row', tid);
        this.header = headers[0];
        this.columns =document.getElementsByClassName('jb_cell', this.header);
        this.columns.each(function(item) {
            item.sortable='true'==Element.readAttribute(item, 'jb_sortable');
            item.editable='true'==Element.readAttribute(item, 'jb_editable');
        });
        
        var selectedRows = document.getElementsByClassName('jb_row_selected', tid);
        if(selectedRows)
            this.selectedRow = selectedRows[0];
        log(this.header, 'columns '+this.columns.length, JBDebugger.DEBUG);
    },
    
    init:function () {
       this.anchorX=0; 
       this.origWidth=0;
       if(this.currentColumn)
            this.currentColumn.style.cursor='default';
       this.currentColumn=null;
       this.elements=null;
       this.rows=null;
       this.innerWidth=0;
       this.origWidth=0;
    },

    synchValues:function() {
      debug('start synchValue');      
      xmlValue = "<table id=\""+this.id+"\">";
      if(this.changed) {
          for(i = 0; i < this.changed.length; i++)
            xmlValue += "<cell name=\""+this.changed[i].name+"\">"+this.changed[i].value+"</cell>"
      }
      xmlValue+="</table>";
      var tid=this.id;
      JB.Ajax.post(JBUtil.getUrl()+'?editAction=change&'+JB.REQ_COMP_ID+'='+tid, xmlValue,
        function (transport)
        {
          JB.renderComp(tid);
        }, null, null      
      );      
      debug('end synchValue');
    },

    createDateEditor:function (ele) {
        if(this.dateEditor!=null)
            return this.dateEditor;
        this.dateEditor = new JB.DateEditor(this.id+"df");
        return this.dateEditor;
    },

    createTextEditor:function (ele) {
        if(this.textEditor!=null)
            return this.textEditor;
        this.textEditor = new JB.TextEditor(this.id+"tf");
        return this.textEditor;
    },
    
    createLovEditor:function (ele) {
        if(this.lovEditor!=null)
            return this.lovEditor;
        this.lovEditor = new JB.LovEditor(this.id+"lf");
        return this.lovEditor;
    },
    getDateType:function(ele) {
        v = ele.id.split('_');
        column = this.columns[v[2]];
        dt = Element.readAttribute(column, 'jb_data_type');
        return dt;
    },
    getEditor:function(ele) {
        var type= this.getDateType(ele);
        if(type=='text')
            this.editor=this.createTextEditor(ele);
        else if(type=='date')
            this.editor=this.createDateEditor(ele);
        else if(type=='lov')
            this.editor=this.createLovEditor(ele);
        else
            this.editor=this.createTextEditor(ele);
            
        this.editor.object = this;
        this.editor.onSetValue= function(cell, newValue) {    
            var cellid = cell.id;
            var myObject = this.object;
            if(myObject.changed==null) {
                myObject.changed = new Array();
            } 
            added = false;
            myObject.changed.each(function(item) {
                if(item.name==cellid)
                {
                    item.value=newValue;
                    added=true;
                }
            });
            if(!added)
                myObject.changed[myObject.changed.length]=({name:cellid, value : newValue});
      
            log(myObject.id, 'onSetValue '+newValue, JBDebugger.DEBUG);
            
            if(JB_DEBUG_MODE)
                myObject.changed.each(function(item) {
                        log(myObject.id, item.name+'='+item.value, JBDebugger.DEBUG);
                    }
                );    
            myObject.unselectCell(myObject.selectedCell);
        };
        return this.editor;
    },
    
    editCell : function(ele) {
        if(this.editor) {
            this.editor.hide();
        }
        if(this.editable||ele.column.editable)
        {
            this.getEditor(ele).show(ele.id);
        }
    },
    
    unselectCell : function(ele) {
        Element.addClassName(ele,"jb_cell");
        Element.removeClassName(ele,"jb_cell_selected");  
        this.selectedCell=null;
    },
    
    selectCell : function (ele, editable) {
    //
        ids = ele.id.split("_");
        ele.col=ids[2];
        ele.row=ids[1];
        ele.column = this.columns[ele.col];

        log(this.selectedCell, ele, JBDebugger.DEBUG);
        if(this.selectedCell!=null && ele.id==this.selectedCell.id)
            return;

        if(this.selectedCell!=null) {
            this.unselectCell(this.selectedCell);
        }
        
        this.selectedCell=ele;
        
        Element.removeClassName(ele,"jb_cell_over");
        Element.removeClassName(ele,"jb_cell");
        Element.toggleClassName(ele,"jb_cell_selected");
        this.editCell(ele);
    },
    
    lastCell : null,
    onCell : function(ele) {
        if(this.lastCell!=null) {
            this.outCell(this.lastCell);
        }
        Element.addClassName(ele,"jb_cell_over");
        this.lastCell=ele;
    },
    outCell : function(ele) {
        Element.removeClassName(ele,"jb_cell_over");
    },
    getCellAt : function(e) {
       cell = this.getCell(e, this.id);
       if(cell!=null)
       {
          this.onCell(cell);
       }
    },
    getCell : function(e, ele) {
        this.cells = document.getElementsByClassName('jb_cell', ele);
        debug('start getCell ' + ele.tagName+ ' ' + ele.id);
        
        selected =null;
        Position.prepare();
        debug('in getCell ' + this.cells);
        this.cells.each(function(item) {
            if(
                Position.withinIncludingScrolloffsets(item, 
                Event.pointerX(e),
                Event.pointerY(e))
            ) {
                selected = item;
            }
        });
        debug('end getCell ' + selected.id);
        return selected;
    },
    
    reset:function() {
        if(!(!this.editor))
            this.editor.hide();
    },
    
    changeColumnWidth :function (ele, width) {
        this.reset();
        var newWidth = this.origWidth + width;
        var rowWidth = this.innerWidth + width;
        if(newWidth<=0) {
            newWidth = 20;
        }
        log("changeColumnWidth", ele.id +' ' + this.rows.length , JBDebugger.DEBUG);
        for(i=0;i<this.elements.length;i++) {
            this.elements[i].style.width=newWidth+'px';
            this.elements[i].parentNode.style.width=newWidth+'px';    
        }
        for(i=0;i<this.rows.length;i++) {
            this.rows[i].style.width=rowWidth+'px';
        }
    },
    sort: function(col) {
        if(this.columns[col].sortable)
        {
            sortByname= Element.readAttribute(this.columns[col],'jb_field_name');
            JB.sortList(this.id, sortByname==null?col:sortByname);
        }
    },
    selectColumn:function(col, x) {
        this.selectedColumn=this.currentColumn;
       log(this.selectedColumn.id, col, JBDebugger.DEBUG);
        if(!this.resizable)
        {
            this.sort(col);
            return;
        }
        this.anchorX = x;
        this.origWidth=parseInt(this.selectedColumn.style.width);
        this.innerWidth=parseInt($(this.id+'_t').style.width);
        this.elements = document.getElementsByClassName(this.id+'_'+col,this.id);
        this.rows = document.getElementsByClassName(this.id+'_row',this.id);     
    }
};

JB.Tables = Class.create();
JB.Tables.prototype = {
    currentTable:null,
    tables: new Array(),
    createTable:function(id) {
        var table = new JB.Table(id);
        this.currentTable=table;
        this.tables[this.tables.length]=table;
        return table;
    },
    findOrCreateTable:function(id) {
        var table=this.findTable(id);
        if(table==null) {
            table = this.createTable(id);
        }else {
            this.currentTable=table;
        }
        return table;
    },
    findTable:function(id) {
        var table=null;
        $A(this.tables).each(function(item) {
            if(item.id==id) {
                table=item;
            }
        }
        );
        return table;
    },
    _i:function(tid) {
       return this.findOrCreateTable(tid);
    },
    initialize: function(id) {
        this.id = id;
    },
    post : function(tid) {
       this._i(tid).synchValues();
    },
    synchronizeScroll : function (tid) {
        var t =  this._i(tid);
        t.reset();
        scrollingElement = $(tid+'_b');
        scrolledElement = $(tid+'_h');
        $(tid+'_h').scrollLeft = $(tid+'_b').scrollLeft;
        t.scrollLeft=$(tid+'_h').scrollLeft;
    },
    onRowSelect:function (e, rid, tid) {
        var t =  this._i(tid);
        var ele = Event.element(e);
        log('onRowSelect', rid, JBDebugger.DEBUG);
        if(rid)
            ele = $(rid);
            
        
        if(t.selectMode=='row')
        {
            if(ele==t.selectedRow)
                return;    
                
            var selectedRows = document.getElementsByClassName('jb_row_selected', tid);
            if(selectedRows)
                t.selectedRow = selectedRows[0];
    
            if(t.selectedRow!=null) {
                Element.removeClassName(t.selectedRow,"jb_row_selected");
            }
            Element.removeClassName(ele,"jb_row_over");
            Element.removeClassName(ele,"jb_row");
            Element.toggleClassName(ele,"jb_row_selected");
            t.selectedRow = ele;
            rowno= ele.id.split("_");
            t.rowNo=rowno[rowno.length-1];
            if(this.editor) {
                this.editor.hide();
            }
            
            //sync server
            onSelectRow = Element.readAttribute(ele.id, "onSelectRow");
            JB.setComponentProperty(t.id, "selected", parseInt(t.rowNo),
              function() {
                if(onSelectRow) {
                    var _f = eval(onSelectRow);
                    if(_f instanceof Function)
                    {
                        _f(dragged, this.draggedOn);
                    }                
                }
                }, false);          
            
        }//else {
            t.selectCell(t.getCell(e, ele));
        //}
    }, 
    onColumnMouseOver : function (e, tid, col) {
    //if e is still in the do not do anything
        var t =this._i(tid);
        var ele = Event.element(e);
        if(t.anchorX!=0 || ele.tagName!='DIV') {
            return;
        }
        Element.removeClassName(ele,"jb_hd");
        Element.addClassName(ele,"jb_hd_over");
    },
    onColumnMouseOut :function (e,  tid, col) {
    //if e is still in the do not do anything
        var t =this._i(tid);
        var ele = Event.element(e);
        var related = e.relatedTarget?e.relatedTarget:e.toElement;
        
        if(related) {
            if(Element.descendantOf(related, ele) )
            return;
        }
        if(t.anchorX!=0) {
            return;
        }
        Element.addClassName(ele,"jb_hd");
        Element.removeClassName(ele,"jb_hd_over");
    },
    onColumnMouseMove :function (e, tid,col) {
        var t =this._i(tid);
        var ele = Event.element(e);
        if(ele.tagName!='DIV') {
            return;
        }
        var pt = JavaBase.EventFactory.getPosition(e);
        var rect = JavaBase.Dimension.getElementRect(ele);
        debug('moving onColumnMouseMove '+pt.left);

        if(t.anchorX!=0) {
            t.changeColumnWidth(t.currentColumn, pt.left-t.anchorX);
            return;
        }

        left = rect.width + rect.left - t.scrollLeft - 4;
        t.currentColumn=ele;
        if(pt.left > left && pt.left<left + 4)
        {
            ele.style.cursor = "col-resize";
            t.resizable=true;
        }else
        {
            ele.style.cursor = "default";
            t.resizable=false;
        }
    },

    onColumnMouseDown:function (e, tid, col) {
       t =this._i(tid);
       t.selectColumn(col, JavaBase.EventFactory.getPosition(e).left);
    },
    
    onColumnMouseUp:function (e, tid, col) {
       this.synchronizeScroll(tid);
       t =this._i(tid);
       var idStr = t.currentColumn.id.substring(0,t.currentColumn.id.length-2);//remove _c
       t.init();
       JB.synchDim(idStr);
    },
    //table mouse event
    onTableMouseOver : function (e, tid) {
        var t =this._i(tid);
    //    JBDebugger.log("enter "+tid)  ;
    },
    
    onTableMouseOut :function (e,  tid) {
        var t =this._i(tid);
   //     JBDebugger.log("out "+tid)  ;
    },
    onTableMouseMove :function (e, tid,col) {
        var t =this._i(tid);
        var pt = JavaBase.EventFactory.getPosition(e);
        if(t.anchorX!=0) {
            t.changeColumnWidth(t.currentColumn, pt.left-t.anchorX);
            return;
        }
   //     ele = t.getCellAt(e);
    },

    onTableMouseDown:function (e, tid, col) {
       t =this._i(tid);
    },
    
    onTableMouseUp:function (e, tid, col) {
       t =this._i(tid);
    },
    //row mouse event
    onRowMouseOver:function (e, rid, tid) {
        t =this._i(tid);
        var ele = Event.element(e);
        if(rid)
            ele = $(rid);
        if(t.selectMode=='row')
        {
            Element.addClassName(ele,"jb_row_over");
        }
    },
    onRowMouseOut:function (e, rid, tid) {
       t =this._i(tid);
        var ele = Event.element(e);
        if(rid)
            ele = $(rid);
        
        if(t.selectMode=='row')
        {
            Element.removeClassName(ele,"jb_row_over");
        }
    },
    onRowMouseMove:function (e, rid, tid) {
    }
}

JBTable = new JB.Tables('seededTables');//global


//Dragging tool, not finished
JB.DraggingTool = Class.create();
JB.DraggingTool.prototype = {
    initialize:function(id) {
        this.id = id;
        this.div = document.createElement('div');
        var _e = this.div;
        _e.id = this.id+'editor';
        _e.style.position="absolute";
        _e.style.top="100px";
        _e.style.left="200px";
        _e.style.width="200px";
        _e.style.width="50px";
        _e.style.display=""; 
        _e.style.border="1px dashed red"; 

        Event.observe(document, 'mousedown', 
            function(evt){
                var element = Event.element(evt);
             //   alert(element.tagName);
//                JBDragTool.select(element);
                return true;
            }
        );
        
        Event.observe(document, 'mousemove', function(evt){
           var element = Event.element(evt);
           return true;
        });
        Event.observe(document, 'mouseup', function(evt){
           var element = Event.element(evt);
           return true;
        });
    },
    select:function(ele) {
        var element = $(ele);
        
        if(Element.readAttribute(element,'designable')!='true')
            return;
            
        if($(JBDragTool.div.id)==null)
        {
            document.body.appendChild(JBDragTool.div);
        }
        JBDragTool.selected = element;
        Position.clone(element, JBDragTool.div);
        divStyle = JBDragTool.div.style;
        divStyle.width = (parseInt(divStyle.width)-4)+'px';
        divStyle.height = (parseInt(divStyle.height)-4)+'px';
    }
}

JBDragTool=new JB.DraggingTool('jbDragTool');

JB.ListBean = Class.create();
JB.ListBean.prototype = {
    initialize:function(id) {
        
    },
    update:function() {
        
    },
    next : function(listId, options) {
        JB.execute(
          {
            method : 'getNextPage',
            component : listId,
            onComplete:function() {
                if(options && options.source)
                    JB.renderComp(options.source);
            }
          });
        
    },
    previous : function (listId, options) {
        JB.execute(
          {
            method : 'getPreviousPage',
            component : listId,
            onComplete:function() {
                if(options && options.source)
                    JB.renderComp(options.source);
            }
          });
         //${listId.nextPage}
    },
    last : function(listId, options) {
        JB.execute(
          {
            method : 'getLastPage',
            component : listId,
            onComplete:function() {
                if(options && options.source)
                    JB.renderComp(options.source);
            }
          });
    },
    first:function(listId, options) {
        JB.execute(
          {
            method : 'getFirstPage',
            component : listId,
            onComplete:function() {
                if(options && options.source)
                    JB.renderComp(options.source);
            }
          });
    },
    page:function(e, listId, page, options) {
        if(!JavaBase.EventFactory.isReturnKey(e)) {
            return;
        }
        JB.setComponentProperty(listId, "currentPage", parseInt(page)-1,
          function() {
                if(options && options.source)
                    JB.renderComp(options.source);
            }, true
        );
    }
}

JBListBean = new JB.ListBean("JBList");
